package com.tim.helper.inactive.remodule;


import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.junit.Test;

import java.io.File;
import java.io.IOException;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;

/**
 * @author Adminis
 * @date 2020年8月12日
 * DESC: 改造控制器
 *  包名更改
 * 	类增加@RestController @Api(tags = "")
 * 	取消@ResponseBody
 * 	方法增加@ApiOperation、@ApiResponses
 * 	去除Model，替换resultMap.put
 * 	返回String时，替换return语句，返回Result
 * 	替换HttpRequest、HttpResponse
 * 	解析方法 参数，构建@ApiImplicitParams
 *  注释前缀：@Description，功能描述
 */
@Slf4j
@Data
public class ControllerAddSwagger {
    public static final Pattern pattern = Pattern.compile("^@[a-zA-Z]{3,8}Mapping");
    public static final String apiParamTemplate = "			@ApiImplicitParam(dataType = \"%1$s\", name = \"%2$s\", value = \"\", paramType = \"%3$s\", required = %4$s),";
    public static String[] annFlags = {"@Description", "功能描述", "@desc"};//注释正文内容标记，填充到注解


    private List<String> list;
    private List<String> newList;
    private String annContent = "";//注解填充内容
    private int mappingMethodFlag = 0;//public声明对象的标识，0类/变量/普通方法，1Mapping方法
    private int returnFlag = 0;//原返回标识，0String，1非String
    private int contentFlag = 0;//类正文标记
    private int currentLoc = 0;
    String destDir = "E:/temp/java/";

    String controllerClassPath = "";
    @Test
    public void remoduleController() throws IOException {
        System.out.println(controllerClassPath);
        list = Files.readAllLines(Paths.get(controllerClassPath));
        newList = new ArrayList<String>();

        for (currentLoc = 0; currentLoc < list.size(); currentLoc++) {
//			System.out.println(list.get(currentLoc));
            newList.addAll(AbstractLineHandler.HANDLER_LIST.get(0).handle(this));
        }
        write2File(newList);
    }

    String pkgPath = "";
    @Test
    public void remodulePackage() throws IOException {
        pkgPath =
                "E:\\gitlab\\xqxc\\app\\app-document\\src\\main\\java\\com\\xqxc\\app\\document\\controller\\riderApp";

        pkgPath = pkgPath.replace("\\", "/");
        Files.walkFileTree(Paths.get(pkgPath), new SimpleFileVisitor<Path>(){
            @Override
            public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
                String pathStr = file.toString().replace("\\", "/");
                if(pathStr.contains("Controller") && pathStr.endsWith(".java")){
                    init(pathStr);
                    remoduleController();
                }
                return super.visitFile(file, attrs);
            }
        });
    }

    private void write2File(List<String> newList) throws IOException {
        int index = controllerClassPath.lastIndexOf('/');
        String fileName = controllerClassPath.substring(++index).replace("Controller", "ApiController");
        String dir = controllerClassPath.substring(pkgPath.length(), index);
//        dir = dir.replace("/controller", "/controller/api");
        fileName = destDir+dir+fileName;
        File dirFile = new File(destDir+dir);
        if(!dirFile.exists()){
            dirFile.mkdirs();
        }
        // 无时创建，覆盖写入。需目录存在
        Files.write(Paths.get(fileName), newList);
        System.out.println("ok");
    }

    private void init(String path) {
        controllerClassPath = path;
        list = null;
        newList = null;
        annContent = "";//注解填充内容
        mappingMethodFlag = 0;//public声明对象的标识，0类/变量/普通方法，1Mapping方法
        returnFlag = 0;//原返回标识，0String，1非String
        contentFlag = 0;//类正文标记
        currentLoc = 0;
    }
    /**
     * 行处理
     * @author Litianlin
     * @date 2020年9月7日
     *
     */
    public interface LineHandler{
        /**
         * 状态类无状态，通过传入对象带入状态。本身不存储状态。
         * 单例模式，避免创建过多对象。
         * @return
         * @author Litianlin
         * @date 2020年9月7日
         */
        List<String> handle(ControllerAddSwagger rc);
    }

    public static abstract class AbstractLineHandler implements LineHandler {
        public static final List<LineHandler> HANDLER_LIST = new ArrayList<>();
        static {
            HANDLER_LIST.add(PackageLineHandler.HANDLER);
            HANDLER_LIST.add(ControllerAnnotationLineHandler.HANDLER);
            HANDLER_LIST.add(ClassNameLineHandler.HANDLER);
            HANDLER_LIST.add(MappingAnnotationLineHandler.HANDLER);
            HANDLER_LIST.add(ResponseBodyAnnotationLineHandler.HANDLER);
            HANDLER_LIST.add(MethodSignatureLineHandler.HANDLER);
            HANDLER_LIST.add(ReturnLineHandler.HANDLER);
            HANDLER_LIST.add(DefaultLineHandler.HANDLER);
        }

        protected int loc;
        protected String content;
        protected String trimedContent;

        protected void init(ControllerAddSwagger rc){
            this.loc = rc.getCurrentLoc();
            this.content = rc.getList().get(loc);
            this.trimedContent = content.trim();
        }

        public List<String> handle(ControllerAddSwagger rc){
            init(rc);
            if(match(rc)) {
                List<String> newList = new ArrayList<>();
                getResult(rc, newList);
                return newList;
            }else {
                int eleIndex = AbstractLineHandler.HANDLER_LIST.indexOf(this);
                return eleIndex!=-1&&AbstractLineHandler.HANDLER_LIST.size()>eleIndex+1 ? AbstractLineHandler.HANDLER_LIST.get(++eleIndex).handle(rc):null;
            }
        }
        /**
         * 是否由当前处理器处理
         * @param rc
         * @return
         * @author Litianlin
         * @date 2020年9月7日
         */
        protected abstract boolean match(ControllerAddSwagger rc);
        /**
         * 获取行处理结果
         * @param rc
         * @param newList
         * @return
         * @author Litianlin
         * @date 2020年9月7日
         */
        protected abstract List<String> getResult(ControllerAddSwagger rc, List<String> newList);
        /**
         * 包行处理器
         * @author Litianlin
         * @date 2020年9月7日
         *
         */
        public static class PackageLineHandler extends AbstractLineHandler {
            //自用，饿汉式单例
            public static final LineHandler HANDLER = new PackageLineHandler();

            @Override
            protected boolean match(ControllerAddSwagger rc) {
                return trimedContent.startsWith("package ");
            }
            @Override
            protected List<String> getResult(ControllerAddSwagger rc, List<String> newList) {
                newList.add(content.replace("controller", "controller.api"));
                //增加必须的导入
                addImports(newList);
                return newList;
            }
            //增加必须的导入
            private void addImports(List<String> newList) {
                newList.add("\n");
                newList.add("import io.swagger.annotations.Api;");
                newList.add("import io.swagger.annotations.ApiImplicitParam;");
                newList.add("import io.swagger.annotations.ApiImplicitParams;");
                newList.add("import io.swagger.annotations.ApiOperation;");
                newList.add("import io.swagger.annotations.ApiResponse;");
                newList.add("import io.swagger.annotations.ApiResponses;");
                newList.add("import com.born.util.http.HttpServletUtils;");
                newList.add("import org.springframework.web.bind.annotation.RestController;");
                newList.add("import java.util.HashMap;");
            }

        }

        /**
         * @Controller注解行处理器
         * @author Litianlin
         * @date 2020年9月7日
         *
         */
        public static class ControllerAnnotationLineHandler extends AbstractLineHandler {
            public static final LineHandler HANDLER = new ControllerAnnotationLineHandler();

            @Override
            protected boolean match(ControllerAddSwagger rc) {
                return trimedContent.startsWith("@Controller");
            }
            @Override
            protected List<String> getResult(ControllerAddSwagger rc, List<String> newList) {
                String annContent = rc.getAnnContent();
                //替换@Controller
                newList.add("@RestController");
                newList.add("@Api(tags = \""+annContent+"\")");
                rc.setAnnContent("");
                return newList;
            }

        }
        /**
         * 类名行处理
         * @author Litianlin
         * @date 2020年9月7日
         *
         */
        public static class ClassNameLineHandler extends AbstractLineHandler {
            public static final LineHandler HANDLER = new ClassNameLineHandler();

            @Override
            protected boolean match(ControllerAddSwagger rc) {
                return trimedContent.startsWith("public class");
            }

            @Override
            protected List<String> getResult(ControllerAddSwagger rc, List<String> newList) {
                //类名处理
                newList.add(content.replace("Controller", "ApiController"));
                rc.setMappingMethodFlag(0);//取消类url标记
                rc.setContentFlag(1);
                return newList;
            }

        }

        /**
         * Mapping行处理，http接口增加swagger声明
         * @author Litianlin
         * @date 2020年9月7日
         *
         */
        public static class MappingAnnotationLineHandler extends AbstractLineHandler {
            public static final LineHandler HANDLER = new MappingAnnotationLineHandler();
            public static final Pattern PATTERN = Pattern.compile("^@[a-zA-Z]{3,8}Mapping");

            @Override
            protected boolean match(ControllerAddSwagger rc) {
                return PATTERN.matcher(trimedContent).find();
            }

            @Override
            protected List<String> getResult(ControllerAddSwagger rc, List<String> newList) {
                int contentFlag = rc.getContentFlag();
                //请求url，增加@ApiOperation、@ApiResponses
                if(contentFlag == 1) {
                    rc.setMappingMethodFlag(1);
                    String annContent = rc.getAnnContent();
                    if(!content.contains("method")) {
                        content = content.replace("@RequestMapping", "@GetMapping");
                    }
                    newList.add(content);
                    newList.add("	@ApiOperation(value = \""+annContent+"\", notes = \""+annContent+"\")");
                    newList.add("	@ApiResponses(value = { @ApiResponse(code = 300, message = \"操作失败\"),");
                    newList.add("			@ApiResponse(code = 200, message = \"操作成功\", response = Result.class) })");
                }else {
                    //类url路径；swagger声明在@Controller行处理
                    content = content.replaceFirst("web/", "web/api/");
                    newList.add(content);
                    rc.setMappingMethodFlag(1);//请求方法标志位置1
                }
                //清空请求注释
                rc.setAnnContent("");
                return newList;
            }

        }
        /**
         * @ResponseBody行处理，移除
         * @author Litianlin
         * @date 2020年9月7日
         *
         */
        public static class ResponseBodyAnnotationLineHandler extends AbstractLineHandler {
            public static final LineHandler HANDLER = new ResponseBodyAnnotationLineHandler();

            @Override
            protected boolean match(ControllerAddSwagger rc) {
                return trimedContent.startsWith("@ResponseBody");
            }

            @Override
            protected List<String> getResult(ControllerAddSwagger rc, List<String> newList) {
                return newList;
            }

        }
        /**
         * 方法签名行处理，方法签名为多行时，合并多行为一行后处理。
         * @author Litianlin
         * @date 2020年9月7日
         *
         */
        public static class MethodSignatureLineHandler extends AbstractLineHandler {
            public static final LineHandler HANDLER = new MethodSignatureLineHandler();

            @Override
            protected boolean match(ControllerAddSwagger rc) {
                return trimedContent.startsWith("public ") && rc.getMappingMethodFlag()==1;
            }

            @Override
            protected List<String> getResult(ControllerAddSwagger rc, List<String> newList) {
                rc.setMappingMethodFlag(0);
                //方法处理，拼接完整的方法签名
                content = replaceContent(content);
                int index = content.indexOf('{');
                int loc = rc.getCurrentLoc();
                while(index==-1) {
                    content += replaceContent(rc.getList().get(++loc));
                    index = content.indexOf('{');
                }
                rc.setCurrentLoc(loc);
                //解析方法 参数，构建@ApiImplicitParams
                genApiParams(newList, content, index);
                return newList;
            }
            //替换返回类型，去除@ResponseBody
            private String replaceContent(String content) {
                return content.replaceAll("public\\s+String", "public Result")
                        .replace("@ResponseBody", "");
            }
            //按方法签名生成api注解。index左大括号位置
            private void genApiParams(List<String> newList, String str, int index) {
                //参数列表
                String argInfo = str.substring(str.indexOf('(')+1, str.lastIndexOf(')'));
                List<String> apiParamList = new ArrayList<String>();//swagger api注解参数
                List<String> appendList = new ArrayList<String>();//声明HashMap、HttpServletRequest等
                List<String> replaceList = new ArrayList<String>();//被替换的Model、HttpServletRequest等
                if(StringUtils.isNotBlank(argInfo)) {
                    //解析方法参数，获取@ApiImplicitParams构建信息，替换Model、HttpServletRequest等的信息
                    parseArgInfo(argInfo, apiParamList, appendList, replaceList);
                }

                //输出swagger @ApiImplicitParams注解；
                if(!apiParamList.isEmpty()) {
                    newList.add("	@ApiImplicitParams({");
                    newList.addAll(apiParamList);
                    newList.add("	})");
                }
                //输出方法签名，替换Model等
                String methodSignature = str.substring(0, ++index);
                for (int i = 0; i < replaceList.size(); i++) {
                    String replace = replaceList.get(i);
                    methodSignature = methodSignature.replace(replace, "");
                }
                //替换方法签名中的无用逗号、多余空格
                methodSignature = methodSignature.replaceAll(",\\s*,", ",")
                        .replaceAll(",\\s*\\)", ")")
                        .replaceAll("\\(\\s*,", "(")
                        .replaceAll("(([^\\s]+)\\s{2,})", "$2 ");
                newList.add(methodSignature);
                //方法体内输出Model等的替换内容
                newList.addAll(appendList);
                String temp = str.substring(index).trim();
                if(StringUtils.isNotBlank(temp)) {
                    newList.add(temp);
                }
            }

            //解析方法参数，获取@ApiImplicitParams构建信息，替换Model、HttpServletRequest等的信息
            private void parseArgInfo(String argInfo, List<String> apiParamList, List<String> appendList,
                                      List<String> replaceList) {
                argInfo = argInfo.replaceAll("\\([^\\)]*\\)", "");//剔除方法参数注解括号及其中内容
                String[] argArr = argInfo.split(",");//分割为参数数组
                for (int j = 0; j < argArr.length; j++) {
                    String argStr = argArr[j];
                    String[] infos = argStr.trim().split("\\s+");
                    int len = infos.length;
                    //无@RequestBody等注解时为2，有时为3
                    if(len>3 || len<2) {
                        throw new RuntimeException(argArr[j]);
                    }
                    //参数类型
                    String argType = infos[len-2].trim();
                    //参数名称
                    String argName = infos[len-1].trim();
                    //替换的Model、HttpServletRequest等
                    switch (argType) {
                        case "Model":
                            replaceList.add(argStr);
                            appendList.add("    	Map<String, Object> resultMap = new HashMap<>(16);");
                            break;
                        case "HttpServletRequest":
                            replaceList.add(argStr);
                            appendList.add("    	HttpServletRequest "+argName+" = HttpServletUtils.getRequest();");
                            break;
                        case "HttpServletResponse":
                            replaceList.add(argStr);
                            appendList.add("    	HttpServletResponse "+argName+" = HttpServletUtils.getResponse();");
                            break;
                        case "HttpSession":
                            replaceList.add(argStr);
                            appendList.add("    	HttpSession "+argName+" = request.getSession();");
                            break;

                        default:
                            //构建swagger @ApiImplicitParam注解；
                            String paramType="query", required="false";
                            if(infos.length==3) {
                                String annotation = infos[0].trim();
                                if("@RequestBody".equals(annotation)) {
                                    continue;//不构建
                                }else if("@PathVariable".equals(annotation)) {
                                    paramType="path";
                                    required="true";
                                }
                            }else if(argType.toLowerCase().endsWith("dto")) {
                                continue;//不构建
                            }
                            String apiParam = String.format(apiParamTemplate, argType, argName, paramType, required);
                            apiParamList.add(apiParam);
                            break;
                    }
                }
            }
        }

        /**
         * 返回行处理
         * @author Litianlin
         * @date 2020年9月7日
         *
         */
        public static class ReturnLineHandler extends AbstractLineHandler {
            public static final LineHandler HANDLER = new ReturnLineHandler();

            @Override
            protected boolean match(ControllerAddSwagger rc) {

                return trimedContent.contains("return ");
            }

            @Override
            protected List<String> getResult(ControllerAddSwagger rc, List<String> newList) {
                //返回值处理，原返回页面的方法，改为返回resultMap
                String add = trimedContent.matches("^return\\s+\"[\\W\\w]+") ? "		return ResultUtil.success(resultMap);" : content;
                newList.add(add);
                return newList;
            }

        }
        /**
         * 默认行处理，普通行处理
         * @author Litianlin
         * @date 2020年9月7日
         *
         */
        public static class DefaultLineHandler extends AbstractLineHandler {
            public static final LineHandler HANDLER = new DefaultLineHandler();

            @Override
            protected boolean match(ControllerAddSwagger rc) {
                return Boolean.TRUE;
            }

            @Override
            protected List<String> getResult(ControllerAddSwagger rc, List<String> newList) {
                String[] annFlags = ControllerAddSwagger.annFlags;
                //找到注释正文内容标记，填充到注解
                int index = -1;
                for (int j = 0; j < annFlags.length; j++) {
                    String annFlag = annFlags[j];
                    //转为全大写后判定
                    index = content.toUpperCase().indexOf(annFlag.toUpperCase());
                    if(index>-1) {
                        index += annFlag.length();
                        String annContent = content.substring(index).trim();
                        if(annContent.indexOf(':')==0 || annContent.indexOf('：')==0) {
                            annContent = annContent.substring(1).trim();
                        }
                        rc.setAnnContent(annContent);
                        break;
                    }
                }
                newList.add(content.replaceAll("model\\.addAttribute", "resultMap.put")
                        .replaceAll("model\\.addAllAttributes", "resultMap.putAll"));
                return newList;
            }

        }

    }





}
